package com.xinlong.shop.framework.security.util;

import com.xinlong.shop.framework.security.constant.SecurityConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author Sylow
 * @Description
 * @Date: Created in 23:22 2022/5/24
 */
@Component
public class TokenUtil {

    private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);

    /**
     * 根据用户信息生成token <br />
     * token和refreshToken共用一个生成方法 <br />
     * refreshToken 过期时间为7天
     * @param userDetails
     * @param refreshToken 是否是刷新token
     */
    public String generateToken(UserDetails userDetails, boolean refreshToken) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(SecurityConstants.TOKEN_USER_CLAIM, userDetails.getUsername());
        claims.put(SecurityConstants.TOKEN_CREATED_CLAIM, new Date());
        logger.debug("生成token时间：" + new Date());
        return generateToken(claims, refreshToken);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            logger.info("JWT格式验证失败:{}",token, e);
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 验证refreshToken是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateRefToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(SecurityConstants.JWT_SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            // 过期也能获取到
            claims = e.getClaims();
        }
        return claims;
    }

    /**
     * 根据负责生成JWT的token
     * refreshToken时间是7天
     * @param claims
     * @param refreshToken 是否是刷新token
     */
    private String generateToken(Map<String, Object> claims,boolean refreshToken) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate(refreshToken))
                .signWith(SignatureAlgorithm.HS512, SecurityConstants.JWT_SECRET_KEY)
                .compact();
    }

    /**
     * 生成token的过期时间
     * @param refreshToken 是否是刷新token
     */
    private Date generateExpirationDate(boolean refreshToken) {
        if (refreshToken) {
            return new Date(System.currentTimeMillis() + SecurityConstants.REFRESH_EXPIRATION_TIME * 1000);
        } else {
            return new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME * 1000);
        }
    }



    public static void main(String[] args) {
        TokenUtil util = new TokenUtil();
//        Map<String, Object> claims = new HashMap<>();
//        claims.put(SecurityConstants.TOKEN_USER_CLAIM, "sylow");
//        claims.put(SecurityConstants.TOKEN_CREATED_CLAIM, new Date());
//        //logger.debug("生成token时间：" + new Date());
//        String token = util.generateToken(claims);
//        System.out.println(util.generateExpirationDate());
//        System.out.println(token);
        String token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE2NjU0MjU0NzAwNTEsImV4cCI6MTY2NTQyNTUzMH0.b37g_vxSfXPN8pyaiB91UCC1mFs3OCdNDApWuDJJNg9UsN0_ylsbTkobYpTaiPTt9offisUVWzucvsRY8ANWKg";
        String username = util.getUserNameFromToken(token);
        System.out.println(username);
    }

}
